package com.autumn.config.services.impl;

import com.alibaba.dubbo.config.annotation.Service;
import com.autumn.common.api.application.dto.output.IPageQueryResult;
import com.autumn.config.api.consts.ConfigureConsts.StatusConsts;
import com.autumn.config.api.dto.input.AppPageQueryInput;
import com.autumn.config.api.dto.input.ApplicationConnectionInput;
import com.autumn.config.api.dto.input.StatusInput;
import com.autumn.config.api.dto.output.ApplicationConnectionOutput;
import com.autumn.config.api.services.IApplicationConnectionService;
import com.autumn.config.api.services.ICacheService;
import com.autumn.config.entities.ApplicationConnection;
import com.autumn.config.entities.ApplicationInfo;
import com.autumn.config.entities.ConnectionConfigure;
import com.autumn.config.entities.view.ApplicationConnectionView;
import com.autumn.config.repositories.IApplicationInfoRepository;
import com.autumn.config.repositories.IConnectionConfigureRepository;
import com.autumn.mybatis.criterion.LockModeEnum;
import com.autumn.util.AutoMapUtils;
import com.autumn.util.DataRollbackException;
import com.autumn.util.ExceptionUtils;
import com.autumn.util.StringUtils;
import com.autumn.util.data.DbAuditingUtils;
import com.autumn.util.data.DbQueryUtils;
import com.autumn.util.data.PageQueryBuilder;
import com.autumn.util.tuple.TupleTwo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;

import java.util.HashMap;
import java.util.Map;

/**
 * 应用连接服务实现
 *
 * @author 老码农
 * <p>
 * Description
 * </p>
 * @date 2018-01-01 15:33:56
 */
@Service(interfaceClass = IApplicationConnectionService.class)
@Component
public class ApplicationConnectionServiceImpl extends
        AbstractConfigureService<ApplicationConnection, ApplicationConnectionView, ApplicationConnectionInput, ApplicationConnectionInput, ApplicationConnectionOutput>
        implements IApplicationConnectionService {

    @Autowired
    private IConnectionConfigureRepository connRepository;

    @Autowired
    private IApplicationInfoRepository appRepository;

    @Autowired
    private ICacheService cacheService;

    private TupleTwo<ApplicationInfo, ConnectionConfigure> checkConnection(ApplicationConnectionInput input) {
        ExceptionUtils.checkNotNull(input, "input");
        if (input.getSortId() == null) {
            input.setSortId(1);
        }
        if (input.getAppId() == null) {
            ExceptionUtils.throwValidationException("应用 id 不能为空。");
        }
        if (input.getConnectionId() == null) {
            ExceptionUtils.throwValidationException("连接 id 不能为空。");
        }
        if (StringUtils.isNullOrBlank(input.getIdentity())) {
            ExceptionUtils.throwValidationException("连接标识不能为空。");
        }
        ApplicationInfo appInfo = DbQueryUtils.queryById(appRepository, ApplicationInfo.class, input.getAppId());
        if (appInfo == null) {
            ExceptionUtils.throwValidationException("指定的应用不存在!");
        }
        ConnectionConfigure connect = DbQueryUtils.queryById(connRepository, ConnectionConfigure.class,
                input.getConnectionId());
        if (connect == null) {
            ExceptionUtils.throwValidationException("指定的连接不存在!");
        }
        return new TupleTwo<>(appInfo, connect);
    }

    private boolean exist(Long appId, String name, Object value) {
        Map<String, Object> propertyMap = new HashMap<>(16);
        propertyMap.put("appId", appId);
        propertyMap.put(name, value);
        return this.exist(propertyMap);
    }

    private final static String IDENTITY_FILED = "identity";
    private final static String CONNECTION_ID_FILED = "connectionId";

    @Override
    @Transactional(rollbackFor = DataRollbackException.class)
    public ApplicationConnectionOutput add(ApplicationConnectionInput input) {
        TupleTwo<ApplicationInfo, ConnectionConfigure> tuple = checkConnection(input);
        if (this.exist(input.getAppId(), IDENTITY_FILED, input.getIdentity())) {
            ExceptionUtils.throwValidationException(String.format("连接标识 %s 在同一应用已重复。", input.getIdentity()));
        }
        if (this.exist(input.getAppId(), CONNECTION_ID_FILED, input.getConnectionId())) {
            ExceptionUtils.throwValidationException(String.format("连接 %s 在同一应用已重复。", tuple.getItem2().getName()));
        }
        ApplicationConnection connectInfo = AutoMapUtils.map(input, ApplicationConnection.class);
        if (connectInfo.getSortId() == null) {
            connectInfo.setSortId(1);
        }
        DbAuditingUtils.insertSetProperty(connectInfo);
        connectInfo.setStatus(StatusConsts.STATUS_DRAFT);
        this.updateDefault(connectInfo);
        this.repository.insert(connectInfo);
        cacheService.deleteServiceInfo(tuple.getItem1().getAppId());
        return AutoMapUtils.map(this.getQueryById(connectInfo.getId()), ApplicationConnectionOutput.class);
    }

    @Override
    @Transactional(rollbackFor = DataRollbackException.class)
    public ApplicationConnectionOutput modify(ApplicationConnectionInput input) {
        if (input == null || input.getId() == null) {
            ExceptionUtils.throwValidationException("Id 不能为空");
        }
        TupleTwo<ApplicationInfo, ConnectionConfigure> tuple = checkConnection(input);

        ApplicationConnection result = this.getById(input.getId(), LockModeEnum.UPDATE);
        if (result == null) {
            ExceptionUtils.throwValidationException(String.format("连接标识 %s 不存在。", input.getIdentity()));
        }
        if (!input.getIdentity().equalsIgnoreCase(result.getIdentity())) {
            if (this.exist(input.getAppId(), IDENTITY_FILED, input.getIdentity())) {
                ExceptionUtils.throwValidationException(String.format("连接标识 %s 在同一应用已重复。", input.getIdentity()));
            }
        }
        if (!input.getConnectionId().equals(result.getConnectionId())) {
            if (this.exist(input.getAppId(), CONNECTION_ID_FILED, input.getConnectionId())) {
                ExceptionUtils.throwValidationException(String.format("连接 %s 在同一应用已重复。", tuple.getItem2().getName()));
            }
        }
        AutoMapUtils.map(input, result);
        DbAuditingUtils.updateSetProperty(result);
        result.setStatus(StatusConsts.STATUS_DRAFT);
        this.updateDefault(result);
        this.repository.update(result);
        return AutoMapUtils.map(this.getQueryById(result.getId()), ApplicationConnectionOutput.class);
    }

    @Override
    @Transactional(rollbackFor = DataRollbackException.class)
    protected ApplicationConnection deleteById(Long id) {
        ApplicationConnection result = super.deleteById(id);
        if (result != null) {
            ApplicationInfo appInfo = appRepository.get(result.getAppId());
            if (appInfo != null) {
                cacheService.deleteServiceInfo(appInfo.getAppId());
            }
        }
        return result;
    }

    @Override
    @Transactional(rollbackFor = DataRollbackException.class)
    public ApplicationConnectionOutput updateStatus(StatusInput input) {
        ApplicationConnectionOutput result = super.updateStatus(input);
        if (result != null) {
            ApplicationInfo appInfo = appRepository.get(result.getAppId());
            if (appInfo != null) {
                cacheService.deleteServiceInfo(appInfo.getAppId());
            }
        }
        return result;
    }

    @Override
    public IPageQueryResult<ApplicationConnectionOutput> queryByPage(AppPageQueryInput input) {
        if (input == null || input.getAppId() == null) {
            ExceptionUtils.throwValidationException("应用Id不能为空");
        }
        PageQueryBuilder<ApplicationConnectionView> builder = new PageQueryBuilder<>(ApplicationConnectionView.class);
        return builder.apply(q -> {
            q.eq("appId", input.getAppId()).orderBy("sortId").orderBy("id");
        }).page(input, this.getPageMaxSize()).toPageResult(this.queryRepository, ApplicationConnectionOutput.class);
    }

}
